package com.flowplan.websocket.service;

import com.flowplan.websocket.dto.CollaborationMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 协作冲突解决服务
 * 处理多用户协作时的冲突检测和智能解决
 * 利用Java 21模式匹配优化冲突处理逻辑
 */
@Slf4j
@Service
public class ConflictResolutionService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    private static final String RESOURCE_VERSION_KEY = "conflict:version:%s";
    private static final String RESOURCE_LOCK_KEY = "conflict:lock:%s";
    private static final String CONFLICT_HISTORY_KEY = "conflict:history:project:%d";

    /**
     * 检测操作冲突
     * 使用Java 21模式匹配优化冲突检测逻辑
     */
    public ConflictDetectionResult detectConflict(CollaborationMessage message) {
        try {
            String resourceKey = generateResourceKey(message.getProjectId(), message.getResourceId());
            String versionKey = String.format(RESOURCE_VERSION_KEY, resourceKey);
            String lockKey = String.format(RESOURCE_LOCK_KEY, resourceKey);

            // 使用模式匹配处理不同类型的操作
            return switch (message.getOperationType()) {
                case "CREATE" -> handleCreateConflict(message, resourceKey);
                case "UPDATE" -> handleUpdateConflict(message, versionKey, lockKey);
                case "DELETE" -> handleDeleteConflict(message, versionKey, lockKey);
                case "MOVE" -> handleMoveConflict(message, resourceKey);
                default -> {
                    log.warn("未知操作类型: {}", message.getOperationType());
                    yield new ConflictDetectionResult(false, "未知操作类型");
                }
            };
            
        } catch (Exception e) {
            log.error("冲突检测异常: {}", e.getMessage(), e);
            return new ConflictDetectionResult(true, "冲突检测失败: " + e.getMessage());
        }
    }

    /**
     * 处理创建操作冲突
     */
    private ConflictDetectionResult handleCreateConflict(CollaborationMessage message, String resourceKey) {
        // 检查资源是否已存在
        Boolean exists = redisTemplate.hasKey(resourceKey);
        if (Boolean.TRUE.equals(exists)) {
            return new ConflictDetectionResult(true, "资源已存在，无法创建");
        }
        
        // 创建初始版本
        redisTemplate.opsForValue().set(resourceKey + ":version", 1, 24, TimeUnit.HOURS);
        return new ConflictDetectionResult(false, "创建操作无冲突");
    }

    /**
     * 处理更新操作冲突
     */
    private ConflictDetectionResult handleUpdateConflict(CollaborationMessage message, 
                                                       String versionKey, String lockKey) {
        // 检查资源锁定状态
        String lockHolder = (String) redisTemplate.opsForValue().get(lockKey);
        if (lockHolder != null && !lockHolder.equals(message.getUserId())) {
            return new ConflictDetectionResult(true, "资源被用户 " + lockHolder + " 锁定");
        }

        // 检查版本冲突
        Long currentVersion = (Long) redisTemplate.opsForValue().get(versionKey);
        Long messageVersion = message.getVersion();
        
        if (currentVersion != null && messageVersion != null && 
            !currentVersion.equals(messageVersion)) {
            return new ConflictDetectionResult(true, 
                "版本冲突: 当前版本 " + currentVersion + ", 操作版本 " + messageVersion);
        }

        return new ConflictDetectionResult(false, "更新操作无冲突");
    }

    /**
     * 处理删除操作冲突
     */
    private ConflictDetectionResult handleDeleteConflict(CollaborationMessage message, 
                                                       String versionKey, String lockKey) {
        // 检查资源是否存在
        Boolean exists = redisTemplate.hasKey(versionKey);
        if (!Boolean.TRUE.equals(exists)) {
            return new ConflictDetectionResult(true, "资源不存在，无法删除");
        }

        // 检查资源锁定状态
        String lockHolder = (String) redisTemplate.opsForValue().get(lockKey);
        if (lockHolder != null && !lockHolder.equals(message.getUserId())) {
            return new ConflictDetectionResult(true, "资源被用户 " + lockHolder + " 锁定");
        }

        return new ConflictDetectionResult(false, "删除操作无冲突");
    }

    /**
     * 处理移动操作冲突
     */
    private ConflictDetectionResult handleMoveConflict(CollaborationMessage message, String resourceKey) {
        // 检查源资源和目标位置
        // 这里可以根据具体业务逻辑实现移动冲突检测
        return new ConflictDetectionResult(false, "移动操作无冲突");
    }

    /**
     * 解决冲突
     * 使用Java 21模式匹配优化冲突解决策略
     */
    public ConflictResolutionResult resolveConflict(CollaborationMessage message, 
                                                   ConflictDetectionResult conflict, 
                                                   String resolutionStrategy) {
        try {
            // 使用模式匹配选择解决策略
            return switch (resolutionStrategy) {
                case "AUTO_MERGE" -> attemptAutoMerge(message, conflict);
                case "FORCE_OVERRIDE" -> forceOverride(message);
                case "USER_CHOOSE" -> requestUserChoice(message, conflict);
                case "LATEST_WINS" -> latestWins(message);
                case "MERGE_CHANGES" -> mergeChanges(message);
                default -> {
                    log.warn("未知解决策略: {}", resolutionStrategy);
                    yield new ConflictResolutionResult(false, "未知解决策略", null);
                }
            };
            
        } catch (Exception e) {
            log.error("冲突解决异常: {}", e.getMessage(), e);
            return new ConflictResolutionResult(false, "冲突解决失败: " + e.getMessage(), null);
        }
    }

    /**
     * 自动合并策略
     */
    private ConflictResolutionResult attemptAutoMerge(CollaborationMessage message, 
                                                     ConflictDetectionResult conflict) {
        // 尝试智能合并，如果无法自动合并则转为手动处理
        if (canAutoMerge(message)) {
            return performAutoMerge(message);
        } else {
            return requestUserChoice(message, conflict);
        }
    }

    /**
     * 强制覆盖策略
     */
    private ConflictResolutionResult forceOverride(CollaborationMessage message) {
        String resourceKey = generateResourceKey(message.getProjectId(), message.getResourceId());
        String versionKey = String.format(RESOURCE_VERSION_KEY, resourceKey);
        
        // 更新版本号
        Long newVersion = redisTemplate.opsForValue().increment(versionKey);
        message.setVersion(newVersion);
        
        // 记录强制覆盖操作
        recordConflictResolution(message, "FORCE_OVERRIDE", "强制覆盖解决冲突");
        
        return new ConflictResolutionResult(true, "强制覆盖成功", message);
    }

    /**
     * 用户选择策略
     */
    private ConflictResolutionResult requestUserChoice(CollaborationMessage message, 
                                                      ConflictDetectionResult conflict) {
        // 发送冲突通知给用户，请求用户做出选择
        CollaborationMessage conflictMessage = new CollaborationMessage();
        conflictMessage.setMessageType("CONFLICT_NOTIFICATION");
        conflictMessage.setOperationType("USER_CHOICE_REQUIRED");
        conflictMessage.setProjectId(message.getProjectId());
        conflictMessage.setUserId(message.getUserId());
        conflictMessage.setResourceId(message.getResourceId());
        conflictMessage.setData(conflict.getMessage());
        conflictMessage.setTimestamp(LocalDateTime.now());
        
        messagingTemplate.convertAndSendToUser(
            message.getUserId(),
            "/queue/conflicts",
            conflictMessage
        );
        
        return new ConflictResolutionResult(false, "等待用户选择解决方案", null);
    }

    /**
     * 最新优先策略
     */
    private ConflictResolutionResult latestWins(CollaborationMessage message) {
        String resourceKey = generateResourceKey(message.getProjectId(), message.getResourceId());
        String versionKey = String.format(RESOURCE_VERSION_KEY, resourceKey);
        
        // 直接使用最新操作
        Long newVersion = redisTemplate.opsForValue().increment(versionKey);
        message.setVersion(newVersion);
        message.setTimestamp(LocalDateTime.now());
        
        recordConflictResolution(message, "LATEST_WINS", "最新操作优先");
        
        return new ConflictResolutionResult(true, "最新操作优先解决", message);
    }

    /**
     * 变更合并策略
     */
    private ConflictResolutionResult mergeChanges(CollaborationMessage message) {
        // 实现智能变更合并逻辑
        // 这里是简化实现，实际项目中需要根据具体数据结构实现
        
        try {
            CollaborationMessage mergedMessage = performSmartMerge(message);
            recordConflictResolution(message, "MERGE_CHANGES", "智能合并变更");
            
            return new ConflictResolutionResult(true, "变更合并成功", mergedMessage);
        } catch (Exception e) {
            log.error("智能合并失败: {}", e.getMessage());
            return requestUserChoice(message, new ConflictDetectionResult(true, "智能合并失败"));
        }
    }

    /**
     * 检查是否可以自动合并
     */
    private boolean canAutoMerge(CollaborationMessage message) {
        // 简单的自动合并判断逻辑
        // 实际项目中需要根据具体业务场景实现
        return "UPDATE".equals(message.getOperationType()) && 
               message.getData() != null && 
               !message.getData().contains("critical_field");
    }

    /**
     * 执行自动合并
     */
    private ConflictResolutionResult performAutoMerge(CollaborationMessage message) {
        // 实现自动合并逻辑
        String resourceKey = generateResourceKey(message.getProjectId(), message.getResourceId());
        String versionKey = String.format(RESOURCE_VERSION_KEY, resourceKey);
        
        Long newVersion = redisTemplate.opsForValue().increment(versionKey);
        message.setVersion(newVersion);
        
        recordConflictResolution(message, "AUTO_MERGE", "自动合并解决");
        
        return new ConflictResolutionResult(true, "自动合并成功", message);
    }

    /**
     * 执行智能合并
     */
    private CollaborationMessage performSmartMerge(CollaborationMessage message) {
        // 智能合并实现
        // 这里是简化版本，实际需要根据数据结构进行复杂的合并操作
        
        CollaborationMessage mergedMessage = new CollaborationMessage();
        mergedMessage.setMessageType(message.getMessageType());
        mergedMessage.setOperationType(message.getOperationType());
        mergedMessage.setUserId(message.getUserId());
        mergedMessage.setProjectId(message.getProjectId());
        mergedMessage.setResourceId(message.getResourceId());
        mergedMessage.setTimestamp(LocalDateTime.now());
        
        // 合并数据
        String mergedData = mergDataFields(message.getData());
        mergedMessage.setData(mergedData);
        
        return mergedMessage;
    }

    /**
     * 合并数据字段
     */
    private String mergDataFields(String data) {
        // 简化的数据合并逻辑
        // 实际项目中需要根据JSON结构进行智能合并
        return data + "_merged_" + System.currentTimeMillis();
    }

    /**
     * 记录冲突解决历史
     */
    private void recordConflictResolution(CollaborationMessage message, String strategy, String description) {
        Thread.startVirtualThread(() -> {
            try {
                String historyKey = String.format(CONFLICT_HISTORY_KEY, message.getProjectId());
                
                ConflictResolutionRecord record = new ConflictResolutionRecord();
                record.setUserId(message.getUserId());
                record.setResourceId(message.getResourceId());
                record.setOperationType(message.getOperationType());
                record.setStrategy(strategy);
                record.setDescription(description);
                record.setTimestamp(LocalDateTime.now());
                
                redisTemplate.opsForList().leftPush(historyKey, record);
                redisTemplate.opsForList().trim(historyKey, 0, 999); // 保留最近1000条记录
                redisTemplate.expire(historyKey, 7, TimeUnit.DAYS);
                
                log.info("记录冲突解决: projectId={}, strategy={}, description={}", 
                        message.getProjectId(), strategy, description);
                
            } catch (Exception e) {
                log.error("记录冲突解决历史异常: {}", e.getMessage(), e);
            }
        });
    }

    /**
     * 生成资源键
     */
    private String generateResourceKey(Long projectId, String resourceId) {
        return "project:" + projectId + ":resource:" + resourceId;
    }

    /**
     * 冲突检测结果
     */
    public static class ConflictDetectionResult {
        private final boolean hasConflict;
        private final String message;

        public ConflictDetectionResult(boolean hasConflict, String message) {
            this.hasConflict = hasConflict;
            this.message = message;
        }

        public boolean hasConflict() { return hasConflict; }
        public String getMessage() { return message; }
    }

    /**
     * 冲突解决结果
     */
    public static class ConflictResolutionResult {
        private final boolean resolved;
        private final String message;
        private final CollaborationMessage resolvedMessage;

        public ConflictResolutionResult(boolean resolved, String message, CollaborationMessage resolvedMessage) {
            this.resolved = resolved;
            this.message = message;
            this.resolvedMessage = resolvedMessage;
        }

        public boolean isResolved() { return resolved; }
        public String getMessage() { return message; }
        public CollaborationMessage getResolvedMessage() { return resolvedMessage; }
    }

    /**
     * 冲突解决记录
     */
    public static class ConflictResolutionRecord {
        private String userId;
        private String resourceId;
        private String operationType;
        private String strategy;
        private String description;
        private LocalDateTime timestamp;

        // Getters and Setters
        public String getUserId() { return userId; }
        public void setUserId(String userId) { this.userId = userId; }
        public String getResourceId() { return resourceId; }
        public void setResourceId(String resourceId) { this.resourceId = resourceId; }
        public String getOperationType() { return operationType; }
        public void setOperationType(String operationType) { this.operationType = operationType; }
        public String getStrategy() { return strategy; }
        public void setStrategy(String strategy) { this.strategy = strategy; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public LocalDateTime getTimestamp() { return timestamp; }
        public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
    }
}